package client

import (
	"fmt"
	pb "go-war3proxy/pkg/proto"
	"go-war3proxy/pkg/utils"
	"net"
	"sync"
	"time"

	"go.uber.org/zap"

	"go-war3proxy/pkg/const"
)

// War3Server 为每个远程war3 game客户端创建的代理，处理TCP和UDP连接
type War3Server struct {
	otherWar3IP               string
	connectionWar3ProxyServer *ConnectionWar3ProxyServer
	logger                    *zap.Logger
	tcpListener               *War3TcpListener
	udpListener               *War3UdpListener
	mutex                     sync.RWMutex
	closed                    bool
}

// NewWar3Server 创建新的War3Server
func NewWar3Server(otherWar3IP string, connectionWar3ProxyServer *ConnectionWar3ProxyServer, logger *zap.Logger) *War3Server {
	return &War3Server{
		otherWar3IP:               otherWar3IP,
		connectionWar3ProxyServer: connectionWar3ProxyServer,
		logger:                    logger.With(zap.String("other_war3_ip", otherWar3IP), zap.String("component", "war3_server")),
	}
}

// Start 启动War3Server
func (ws *War3Server) Start() {
	ws.logger.Info("启动War3Server")

	ws.mutex.Lock()
	if ws.closed {
		ws.mutex.Unlock()
		return
	}

	// 启动TCP监听器
	ws.tcpListener = NewWar3TcpListener(ws.otherWar3IP, ws.connectionWar3ProxyServer, ws.logger)

	// 启动UDP监听器
	ws.udpListener = NewWar3UdpListener(ws.otherWar3IP, ws.connectionWar3ProxyServer, ws.logger)
	ws.mutex.Unlock()

	// 在单独的goroutine中启动监听器
	tcpDone := make(chan struct{})
	udpDone := make(chan struct{})

	go func() {
		defer func() { tcpDone <- struct{}{} }()
		ws.tcpListener.Start()
	}()

	go func() {
		defer func() { udpDone <- struct{}{} }()
		ws.udpListener.Start()
	}()

	// 等待任一监听器结束
	select {
	case <-tcpDone:
		ws.logger.Info("TCP监听器结束")
	case <-udpDone:
		ws.logger.Info("UDP监听器结束")
	}

	// 关闭所有组件
	ws.Close()
}

// Close 关闭War3Server
func (ws *War3Server) Close() {
	ws.mutex.Lock()
	defer ws.mutex.Unlock()

	if ws.closed {
		return
	}

	ws.closed = true
	ws.logger.Info("关闭War3Server")

	// 关闭TCP监听器
	if ws.tcpListener != nil {
		ws.tcpListener.Close()
		ws.tcpListener = nil
	}

	// 关闭UDP监听器
	if ws.udpListener != nil {
		ws.udpListener.Close()
		ws.udpListener = nil
	}
}

// UDPSend 发送UDP数据
func (ws *War3Server) UDPSend(data []byte) {
	ws.mutex.RLock()
	udpListener := ws.udpListener
	ws.mutex.RUnlock()

	if udpListener != nil {
		ws.logger.Debug("发送UDP数据", zap.Int("size", len(data)))
		udpListener.Send(data)
	} else {
		ws.logger.Error("UDP监听器为空，无法发送数据")
	}
}

// GetOtherWar3IP 获取其他War3 IP
func (ws *War3Server) GetOtherWar3IP() string {
	return ws.otherWar3IP
}

// War3TcpListener TCP监听器
type War3TcpListener struct {
	otherWar3IP               string
	connectionWar3ProxyServer *ConnectionWar3ProxyServer
	logger                    *zap.Logger
	listener                  net.Listener
	closed                    bool
	mutex                     sync.RWMutex
}

// NewWar3TcpListener 创建新的TCP监听器
func NewWar3TcpListener(otherWar3IP string, connectionWar3ProxyServer *ConnectionWar3ProxyServer, logger *zap.Logger) *War3TcpListener {
	return &War3TcpListener{
		otherWar3IP:               otherWar3IP,
		connectionWar3ProxyServer: connectionWar3ProxyServer,
		logger:                    logger.With(zap.String("component", "tcp_listener")),
	}
}

// Start 启动TCP监听器
func (wtl *War3TcpListener) Start() {
	address := fmt.Sprintf("%s:%d", wtl.otherWar3IP, consts.War3Port)

	wtl.logger.Info("启动TCP监听", zap.String("address", address))

	listener, err := net.Listen("tcp", address)
	if err != nil {
		wtl.logger.Error("TCP监听失败", zap.Error(err))
		return
	}

	wtl.mutex.Lock()
	wtl.listener = listener
	wtl.mutex.Unlock()

	defer func() {
		wtl.mutex.Lock()
		wtl.listener = nil
		wtl.mutex.Unlock()
		listener.Close()
	}()

	wtl.logger.Info("TCP监听启动成功", zap.String("address", address))

	for {
		conn, err := listener.Accept()
		if err != nil {
			wtl.mutex.RLock()
			closed := wtl.closed
			wtl.mutex.RUnlock()

			if closed {
				wtl.logger.Info("TCP监听器已关闭")
				return
			}

			wtl.logger.Error("接受TCP连接失败", zap.Error(err))
			continue
		}

		wtl.logger.Info("接受新的TCP连接", zap.String("remote_addr", conn.RemoteAddr().String()))

		// 每个新连接交给单独的goroutine处理
		go wtl.handleConnection(conn)
	}
}

// handleConnection 处理TCP连接
func (wtl *War3TcpListener) handleConnection(conn net.Conn) {
	defer conn.Close()

	// 获取服务器地址
	serverIP := wtl.connectionWar3ProxyServer.client.GetServerIP()
	serverPort := wtl.connectionWar3ProxyServer.client.GetServerPort()

	// 连接到代理服务器
	proxyConn, err := net.DialTimeout("tcp",
		fmt.Sprintf("%s:%d", serverIP, serverPort),
		time.Duration(consts.TimeoutSecond)*time.Second)
	if err != nil {
		wtl.logger.Error("连接代理服务器失败", zap.Error(err))
		return
	}
	defer proxyConn.Close()

	wtl.logger.Info("连接代理服务器成功", zap.String("proxy_addr", proxyConn.RemoteAddr().String()))

	// 发送WAR3_CONNECT消息
	war3ConnectMessage := &pb.War3Message{
		Type:     pb.MessageType_WAR3_CONNECT,
		TargetIp: wtl.otherWar3IP,
		Payload:  nil,
	}

	if err := utils.SendProtobufMessage(proxyConn, war3ConnectMessage, wtl.logger); err != nil {
		wtl.logger.Error("发送WAR3_CONNECT消息失败", zap.Error(err))
		return
	}

	wtl.logger.Info("发送WAR3_CONNECT消息成功", zap.String("target_ip", wtl.otherWar3IP))

	// 开始TCP数据转发
	wtl.logger.Info("开始TCP数据转发")

	// 双向数据转发
	done := make(chan struct{})

	go func() {
		defer func() { done <- struct{}{} }()
		utils.TransferData(proxyConn, conn, wtl.logger)
	}()

	go func() {
		defer func() { done <- struct{}{} }()
		utils.TransferData(conn, proxyConn, wtl.logger)
	}()

	// 等待任一方向完成
	<-done

	wtl.logger.Info("TCP数据转发结束")
}

// Close 关闭TCP监听器
func (wtl *War3TcpListener) Close() {
	wtl.mutex.Lock()
	defer wtl.mutex.Unlock()

	if wtl.closed {
		return
	}

	wtl.closed = true
	wtl.logger.Info("关闭TCP监听器")

	if wtl.listener != nil {
		wtl.listener.Close()
	}
}

// War3UdpListener UDP监听器
type War3UdpListener struct {
	otherWar3IP               string
	connectionWar3ProxyServer *ConnectionWar3ProxyServer
	logger                    *zap.Logger
	conn                      net.PacketConn
	closed                    bool
	mutex                     sync.RWMutex
}

// NewWar3UdpListener 创建新的UDP监听器
func NewWar3UdpListener(otherWar3IP string, connectionWar3ProxyServer *ConnectionWar3ProxyServer, logger *zap.Logger) *War3UdpListener {
	return &War3UdpListener{
		otherWar3IP:               otherWar3IP,
		connectionWar3ProxyServer: connectionWar3ProxyServer,
		logger:                    logger.With(zap.String("component", "udp_listener")),
	}
}

// Start 启动UDP监听器
func (wul *War3UdpListener) Start() {
	address := fmt.Sprintf("%s:%d", wul.otherWar3IP, consts.War3Port)

	wul.logger.Info("启动UDP监听", zap.String("address", address))

	conn, err := net.ListenPacket("udp", address)
	if err != nil {
		wul.logger.Error("UDP监听失败", zap.Error(err))
		return
	}

	// 设置为广播模式
	if udpConn, ok := conn.(*net.UDPConn); ok {
		if err := udpConn.SetReadBuffer(1024 * 1024); err != nil {
			wul.logger.Warn("设置UDP读缓冲区失败", zap.Error(err))
		}
	}

	wul.mutex.Lock()
	wul.conn = conn
	wul.mutex.Unlock()

	defer func() {
		wul.mutex.Lock()
		wul.conn = nil
		wul.mutex.Unlock()
		conn.Close()
	}()

	wul.logger.Info("UDP监听启动成功", zap.String("address", address))

	buffer := make([]byte, 1024)
	for {
		wul.mutex.RLock()
		currentConn := wul.conn
		wul.mutex.RUnlock()

		if currentConn == nil {
			return
		}

		n, addr, err := currentConn.ReadFrom(buffer)
		if err != nil {
			wul.mutex.RLock()
			closed := wul.closed
			wul.mutex.RUnlock()

			if closed {
				wul.logger.Info("UDP监听器已关闭")
				return
			}

			wul.logger.Error("读取UDP数据失败", zap.Error(err))
			continue
		}

		// 收到其他IP的UDP数据，转发给代理服务器
		// 提取IP地址（去掉端口）
		var fromIP string
		if udpAddr, ok := addr.(*net.UDPAddr); ok {
			fromIP = udpAddr.IP.String()
		} else {
			fromIP = addr.String()
		}

		if fromIP != wul.otherWar3IP {
			wul.logger.Info("收到UDP数据",
				zap.String("from_addr", addr.String()),
				zap.String("from_ip", fromIP),
				zap.Int("size", n))

			if err := wul.connectionWar3ProxyServer.ForwardUdpDataToServer(wul.otherWar3IP, buffer, n); err != nil {
				wul.logger.Error("转发UDP数据失败", zap.Error(err))
			}
		}
	}
}

// Send 发送UDP数据
func (wul *War3UdpListener) Send(data []byte) {
	wul.mutex.RLock()
	conn := wul.conn
	wul.mutex.RUnlock()

	if conn == nil {
		wul.logger.Error("UDP连接为空，无法发送数据")
		return
	}

	// 获取子网广播地址
	broadcastAddr, err := wul.getSubnetBroadcastAddress()
	if err != nil {
		wul.logger.Error("获取广播地址失败", zap.Error(err))
		// 使用默认广播地址
		broadcastAddr = &net.UDPAddr{
			IP:   net.ParseIP(consts.BroadcastAddress),
			Port: consts.War3Port,
		}
	}

	wul.logger.Info("发送UDP数据",
		zap.String("broadcast_addr", broadcastAddr.String()),
		zap.Int("size", len(data)))

	_, err = conn.WriteTo(data, broadcastAddr)
	if err != nil {
		wul.logger.Error("发送UDP数据失败", zap.Error(err))
	}
}

// getSubnetBroadcastAddress 获取子网广播地址
func (wul *War3UdpListener) getSubnetBroadcastAddress() (*net.UDPAddr, error) {
	wul.mutex.RLock()
	conn := wul.conn
	wul.mutex.RUnlock()

	if conn == nil {
		return nil, fmt.Errorf("连接为空")
	}

	localAddr := conn.LocalAddr().(*net.UDPAddr)
	ifaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	for _, iface := range ifaces {
		addrs, err := iface.Addrs()
		if err != nil {
			continue
		}

		for _, addr := range addrs {
			if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.Equal(localAddr.IP) {
				// 计算广播地址
				broadcast := make(net.IP, len(ipNet.IP))
				for i := 0; i < len(ipNet.IP); i++ {
					broadcast[i] = ipNet.IP[i] | ^ipNet.Mask[i]
				}

				return &net.UDPAddr{
					IP:   broadcast,
					Port: consts.War3Port,
				}, nil
			}
		}
	}

	// 如果找不到子网广播地址，返回默认值
	return &net.UDPAddr{
		IP:   net.ParseIP(consts.BroadcastAddress),
		Port: consts.War3Port,
	}, nil
}

// Close 关闭UDP监听器
func (wul *War3UdpListener) Close() {
	wul.mutex.Lock()
	defer wul.mutex.Unlock()

	if wul.closed {
		return
	}

	wul.closed = true
	wul.logger.Info("关闭UDP监听器")

	if wul.conn != nil {
		wul.conn.Close()
	}
}
